package utils;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.util.Arrays;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

/**
 * 支持HMAC-SHA1消息签名工具类.
 * 
 * 支持Hex与Base64两种编码方式.
 * 
 * @author ssl
 */
public class Cryptos {

	private static final String HMACSHA1 = "HmacSHA1";

	private static final int DEFAULT_HMACSHA1_KEYSIZE = 160; // RFC2401

	// -- HMAC-SHA1 funciton --//
	/**
	 * 使用HMAC-SHA1进行消息签名, 返回字节数组,长度为20字节.
	 * 
	 * @param input
	 *            原始输入字符数组
	 * @param key
	 *            HMAC-SHA1密钥
	 */
	public static byte[] hmacSha1(byte[] input, byte[] key) {

		SecretKey secretKey = new SecretKeySpec(key, HMACSHA1);
		Mac mac = null;
		try {
			mac = Mac.getInstance(HMACSHA1);
			mac.init(secretKey);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return mac.doFinal(input);

	}

	/**
	 * 使用HMAC-SHA1进行消息签名, 返回base64编码后的字符串.
	 * 
	 * @param input
	 *            原始输入字符串
	 * @param key
	 *            经过base64编码后的HMAC-SHA1密钥
	 * @return
	 */
	public static String hmacSha1(String input, String key) {

		byte[] inp = null;
		byte[] k = Base64.decodeBase64(key);
		SecretKey secretKey = new SecretKeySpec(k, HMACSHA1);
		Mac mac = null;

		try {
			inp = input.getBytes("UTF-8");
			mac = Mac.getInstance(HMACSHA1);
			mac.init(secretKey);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return Base64.encodeBase64String(mac.doFinal(inp));

	}

	/**
	 * 校验HMAC-SHA1签名是否正确.
	 * 
	 * @param expected
	 *            已存在的签名
	 * @param input
	 *            原始输入字符串
	 * @param key
	 *            密钥
	 */
	public static boolean isMacValid(byte[] expected, byte[] input, byte[] key) {
		byte[] actual = hmacSha1(input, key);
		return Arrays.equals(expected, actual);
	}

	/**
	 * 校验HMAC-SHA1签名是否正确.
	 * 
	 * @param expected
	 *            经过base64编码后的消息签名
	 * @param input
	 * @param key
	 *            经过base64编码后的key
	 * @return
	 */
	public static boolean isMacValid(String expected, String input, String key) {
		byte[] inp = null;
		try {
			inp = input.getBytes("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		byte[] k = Base64.decodeBase64(key);
		byte[] actual = hmacSha1(inp, k);
		byte[] exp = Base64.decodeBase64(expected);
		return Arrays.equals(exp, actual);

	}

	/**
	 * 生成HMAC-SHA1密钥,返回字节数组,长度为160位(20字节). HMAC-SHA1算法对密钥无特殊要求,
	 * RFC2401建议最少长度为160位(20字节).
	 */
	public static byte[] generateHmacSha1Key() {
		try {
			KeyGenerator keyGenerator = KeyGenerator.getInstance(HMACSHA1);
			keyGenerator.init(DEFAULT_HMACSHA1_KEYSIZE);
			SecretKey secretKey = keyGenerator.generateKey();
			return secretKey.getEncoded();
		} catch (GeneralSecurityException e) {
			e.printStackTrace();
			return null;
		}
	}

	public static void main(String[] args) throws Exception {
		String key = Base64.encodeBase64String(generateHmacSha1Key());
		System.out.println("key:" + key);
		// String input = "8";
		// String expected =
		// Base64.encodeBase64String(hmacSha1(input.getBytes(),
		// Base64.decodeBase64(key)));
		// System.out.println("expected:" + expected);
		// System.out
		// .println(isMacValid(Base64.decodeBase64(expected),
		// input.getBytes("utf-8"), Base64.decodeBase64(key)));
		String input = "123";
		String expected = hmacSha1(input, key);
		System.out.println(expected);
		System.out.println(isMacValid(expected, "123", key));

	}
}